package com.example.demo.util;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.internal.LinkedTreeMap;
import com.google.gson.reflect.TypeToken;
import com.orhanobut.logger.Logger;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
 * json 工具类.
 * 在json转换出现异常会拦截忽略
 * Created by xiaolu on 2023/6/7
 */
public class MyJson {

    static Gson gson = createMapGson();

    public static String toJson(Object object) {
        try {
            return gson.toJson(object);
        }
        catch (Exception ex) {
            Logger.e(ex, ex.getMessage());
            return null;
        }
    }

    public static Map fromMap(String json) {
        try {

            Map m = gson.fromJson(json, new TypeToken<Map<String, Object>>() {
            }.getType());
            return m;
        }
        catch (Exception ex) {
            Logger.e(ex, ex.getMessage());
            return null;
        }
    }

    public static <T> T fromJson(String json, Class<T> classOfT) {
        try {
            return gson.fromJson(json, classOfT);
        }
        catch (Exception ex) {
            Logger.e(ex, ex.getMessage());
            return null;
        }
    }

    public static <T> T fromJson(String json, Type typeOfT) {
        try {
            return gson.fromJson(json, typeOfT);
        }
        catch (Exception ex) {
            Logger.e(ex, ex.getMessage());
            return null;
        }
    }

    private static Gson createMapGson() {
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.registerTypeAdapter(new TypeToken<Map<String, Object>>() {
        }.getType(), new MapDeserializerDoubleAsIntFix());
        Gson gson = gsonBuilder.create();
        return gson;
    }

    public static class MapDeserializerDoubleAsIntFix
        implements JsonDeserializer<Object> {

        @Override
        @SuppressWarnings ( "unchecked" )
        public Object deserialize(JsonElement json, Type typeOfT,
            JsonDeserializationContext context) throws JsonParseException {
            return read(json);
        }

        public Object read(JsonElement in) {

            if (in.isJsonArray()) {
                List<Object> list = new ArrayList<Object>();
                JsonArray arr = in.getAsJsonArray();
                for (JsonElement anArr : arr) {
                    list.add(read(anArr));
                }
                return list;
            } else if (in.isJsonObject()) {
                Map<String, Object> map = new LinkedTreeMap<String, Object>();
                JsonObject obj = in.getAsJsonObject();
                Set<Entry<String, JsonElement>> entitySet = obj.entrySet();
                for (Entry<String, JsonElement> entry : entitySet) {
                    map.put(entry.getKey(), read(entry.getValue()));
                }
                return map;
            } else if (in.isJsonPrimitive()) {
                JsonPrimitive prim = in.getAsJsonPrimitive();
                if (prim.isBoolean()) {
                    return prim.getAsBoolean();
                } else if (prim.isString()) {
                    return prim.getAsString();
                } else if (prim.isNumber()) {

                    Number num = prim.getAsNumber();

                    if (Math.ceil(num.doubleValue()) == num.intValue()) {
                        return num.intValue();
                    } else if (Math.ceil(num.doubleValue()) == num.longValue()) {
                        return num.longValue();
                    } else {
                        return num.doubleValue();
                    }
                }
            }
            return null;
        }
    }
}
